using System;
using System.Runtime.InteropServices;

namespace ThaiLanguageTools
{
    //===============================================================
    // Wordbreaker stuff
    //===============================================================
    [Flags]
    public enum WORDREP_BREAK_TYPE
    {
        WORDREP_BREAK_EOW = 0,
        WORDREP_BREAK_EOS = 1,
        WORDREP_BREAK_EOP = 2,
        WORDREP_BREAK_EOC = 3
    }

    [ComImport]
    [Guid("CC907054-C058-101A-B554-08002B33B0E6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IWordSink
    {
        void PutWord([MarshalAs(UnmanagedType.U4)] int cwc,
              [MarshalAs(UnmanagedType.LPWStr)] string pwcInBuf,
              [MarshalAs(UnmanagedType.U4)] int cwcSrcLen,
              [MarshalAs(UnmanagedType.U4)] int cwcSrcPos);
        void PutAltWord([MarshalAs(UnmanagedType.U4)] int cwc,
              [MarshalAs(UnmanagedType.LPWStr)] string pwcInBuf,
              [MarshalAs(UnmanagedType.U4)] int cwcSrcLen,
              [MarshalAs(UnmanagedType.U4)] int cwcSrcPos);
        void StartAltPhrase();
        void EndAltPhrase();
        void PutBreak(WORDREP_BREAK_TYPE breakType);
    }

    [ComImport]
    [Guid("CC906FF0-C058-101A-B554-08002B33B0E6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPhraseSink
    {
        void PutSmallPhrase([MarshalAs(UnmanagedType.LPWStr)] string pwcNoun,
              [MarshalAs(UnmanagedType.U4)] int cwcNoun,
              [MarshalAs(UnmanagedType.LPWStr)] string pwcModifier,
              [MarshalAs(UnmanagedType.U4)] int cwcModifier,
              [MarshalAs(UnmanagedType.U4)] int ulAttachmentType);
        void PutPhrase([MarshalAs(UnmanagedType.LPWStr)] string pwcPhrase,
              [MarshalAs(UnmanagedType.U4)] int cwcPhrase);
    }

    public class CWordSink : IWordSink
    {
        #region CWordSink Members
        public void PutWord(int cwc, string pwcInBuf, int cwcSrcLen, int cwcSrcPos)
        {
            Console.WriteLine("PutWord buffer: " + pwcInBuf.Substring(0, cwc));
        }
        public void PutAltWord(int cwc, string pwcInBuf, int cwcSrcLen, int cwcSrcPos)
        {
            Console.WriteLine("PutAltWord buffer: " + pwcInBuf.Substring(0, cwc));
        }
        public void StartAltPhrase()
        {
            Console.WriteLine("StartAltPhrase");
        }
        public void EndAltPhrase()
        {
            Console.WriteLine("EndAltPhrase");
        }
        public void PutBreak(WORDREP_BREAK_TYPE breakType)
        {
            string strBreak;
            switch (breakType)
            {
                case WORDREP_BREAK_TYPE.WORDREP_BREAK_EOC:
                    strBreak = "EOC";
                    break;
                case WORDREP_BREAK_TYPE.WORDREP_BREAK_EOP:
                    strBreak = "EOP";
                    break;
                case WORDREP_BREAK_TYPE.WORDREP_BREAK_EOS:
                    strBreak = "EOS";
                    break;
                case WORDREP_BREAK_TYPE.WORDREP_BREAK_EOW:
                    strBreak = "EOW";
                    break;
                default:
                    strBreak = "ERROR";
                    break;
            }
            Console.WriteLine("PutBreak : " + strBreak);
        }
        #endregion
    }

    public class CPhraseSink : IPhraseSink
    {
        #region CPhraseSink Members
        public void PutSmallPhrase(string pwcNoun, int cwcNoun,
                string pwcModifier, int cwcModifier, int ulAttachmentType)
        {
            Console.WriteLine("PutSmallPhrase: " + pwcNoun.Substring(0, cwcNoun)
              + " , " + pwcModifier.Substring(0, cwcModifier));
        }
        public void PutPhrase(string pwcPhrase, int cwcPhrase)
        {
            Console.WriteLine("PutPhrase: " + pwcPhrase.Substring(0, cwcPhrase));
        }
        #endregion
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct TEXT_SOURCE
    {
        [MarshalAs(UnmanagedType.FunctionPtr)]
        public delFillTextBuffer pfnFillTextBuffer;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string awcBuffer;
        [MarshalAs(UnmanagedType.U4)]
        public int iEnd;
        [MarshalAs(UnmanagedType.U4)]
        public int iCur;
    }

    // used to fill the buffer for TEXT_SOURCE
    public delegate uint delFillTextBuffer([MarshalAs(UnmanagedType.Struct)]
      ref TEXT_SOURCE pTextSource);

    [ComImport]
    [Guid("D53552C8-77E3-101A-B552-08002B33B0E6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IWordBreaker
    {
        void Init([MarshalAs(UnmanagedType.Bool)] bool fQuery,
              [MarshalAs(UnmanagedType.U4)] int maxTokenSize,
              [MarshalAs(UnmanagedType.Bool)] out bool pfLicense);
        void BreakText([MarshalAs(UnmanagedType.Struct)] ref TEXT_SOURCE pTextSource,
              [MarshalAs(UnmanagedType.Interface)] IWordSink pWordSink,
              [MarshalAs(UnmanagedType.Interface)] IPhraseSink pPhraseSink);
        void GetLicenseToUse([MarshalAs(UnmanagedType.LPWStr)] out string ppwcsLicense);
    }

    // Change the guid for different language
    // 

    // Stemmers listed under
    // HKLM\SYSTEM\CurrentControlSet\Control\ContentIndex\Language
    [ComImport]
    [Guid("80A3E9B0-A246-11D3-BB8C-0090272FA362")]
    //[Guid("369647e0-17b0-11ce-9950-00aa004bbb1f")]
    //[Guid("9717fc70-c1bc-11d0-9692-00a0c908146e")]
    public class EnWordBreaker { }

    // Thai
    // Stemmer: {cedc01c7-59fe-11d1-bbff-00c04fb97fda} // what is there to stem in Thai!?
    // Word breaker: {cca22cf4-59fe-11d1-bbff-00c04fb97fda}
    [ComImport]
    [Guid("cca22cf4-59fe-11d1-bbff-00c04fb97fda")]
    public class ThWordBreaker { }

    public static class WordBreakerMain
    {
        static uint pfnFillTextBuffer(ref TEXT_SOURCE pTextSource)
        {
            Console.WriteLine("pfnFillTextBuffer");
            // return WBREAK_E_END_OF_TEXT
            return 0x80041780;
        }
        //[STAThread]
        public static void Run(String text)
        {
            try
            {
                IWordBreaker wordBreaker = (IWordBreaker)new ThWordBreaker();
                
                CWordSink cws = new CWordSink();
                IWordSink wordSink = (IWordSink)cws;
                
                CPhraseSink cps = new CPhraseSink();
                IPhraseSink phraseSink = (IPhraseSink)cps;
                
                bool pfLicense = true;
                wordBreaker.Init(true, 1000, out pfLicense);
                
                string tokStr = text;
                TEXT_SOURCE pTextSource = new TEXT_SOURCE();
                pTextSource.pfnFillTextBuffer = new delFillTextBuffer(pfnFillTextBuffer);
                pTextSource.awcBuffer = tokStr;
                pTextSource.iCur = 0;
                pTextSource.iEnd = tokStr.Length;

                wordBreaker.BreakText(ref pTextSource, wordSink, phraseSink);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
                return;
            }
        }
    }
}
